package com.alvin.abp.domain.validator;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;

import com.alvin.abp.domain.AlvinUser;
import com.alvin.abp.service.UserService;
/**
 * Validation for user.
 * @author <a href="mailto:rex2.mj@gmail.com">Leo Meng</a>
 * @date $Date: Mar 25, 2013 $
 *
 */
@Component
public class UserValidator implements Validator {
	private static final int MAX_LENGTH = 12;
	private static final int MAX_USERNAME = 30;
	private static final int MAX_MOBILE = 11;
	private static final String passwordPattern = "^.*(?=.{6,12}).*$";
	private static final String mobilePattern = "^((13[0-9])|(15[^4,\\D])|(18[0-9]))\\d{8}$";
	
	@Autowired
	private UserService userService;

	public boolean supports(Class clazz) {
		return AlvinUser.class == clazz;
	}

	public void validate(Object target, Errors errors) {
		AlvinUser user = (AlvinUser) target;
		ValidationUtils.rejectIfEmpty(errors, "mobile", "error.required",
				new Object[] { new DefaultMessageSourceResolvable(
						"user.mobile") });
		ValidationUtils.rejectIfEmpty(errors, "userName", "error.required",
				new Object[] { new DefaultMessageSourceResolvable(
						"user.userName") });
		ValidationUtils.rejectIfEmpty(errors, "password", "error.required",
				new Object[] { new DefaultMessageSourceResolvable(
						"user.password") });
		if (!errors.hasErrors()) {
			if(user.getUserName().length() > MAX_USERNAME){
				errors.rejectValue("userName", "error.userName.length",new Object[]{MAX_USERNAME},"");
			}
			
			if(user.getMobile().length() > MAX_MOBILE){
				errors.rejectValue("mobile", "error.mobile.length",new Object[]{MAX_MOBILE},"");
			}else{
				AlvinUser alvinUser = userService.loadUserBasicInfo(user.getMobile());
				if(alvinUser != null){
					errors.rejectValue("mobile", "error.user.mobile.exists",new Object[]{user.getMobile()},"");
				}
			}
			
			if (!UserValidator.passwordIsValid(user.getMobile(), user.getPassword())){
				errors.rejectValue("password", "error.invalid.user", new Object[]{new DefaultMessageSourceResolvable(
				"user.password")}, "");
			}else if(!user.getPassword().equals(user.getPassword())){
					errors.rejectValue("confirmPassword", "no.matching.password");
			}else{
				Pattern pattern = Pattern.compile(mobilePattern);
				Matcher matcher = pattern.matcher(user.getMobile());		
				if(!matcher.matches()){
					errors.rejectValue("mobile", "error.mobile.invalid");
				}				
			}
		}
		

	}
	
	public void validMobile(String mobile, Errors errors) {
		ValidationUtils.rejectIfEmpty(errors, "mobile", "error.required",
				new Object[] { new DefaultMessageSourceResolvable("user.mobile") });
		if(mobile.length() > MAX_MOBILE){
			errors.rejectValue("mobile", "error.mobile.length",new Object[]{MAX_MOBILE},"");
		}else{
			Pattern pattern = Pattern.compile(mobilePattern);
			Matcher matcher = pattern.matcher(mobile);		
			if(!matcher.matches()){
				errors.rejectValue("mobile", "error.mobile.invalid");
			}else{
				AlvinUser alvinUser = userService.loadUserBasicInfo(mobile);
				if(alvinUser != null){
					errors.rejectValue("mobile", "error.user.mobile.exists",new Object[]{mobile},"");
				}
			}			
		}
		
	}
	
    private static boolean passwordIsValid(String userName, String password) {
        if (password != null) {
            // Has to be 8-20 chars, upper and lower; at least 1 digit, and at least one special char
            if (password.length() > MAX_LENGTH) {
            	return false;
            }
            Pattern pattern = Pattern.compile(passwordPattern);
            Matcher matcher = pattern.matcher(password);
            return matcher.matches();
        }
        return false;
    }	
    
}
